/*
 * Project mapleOnline Korean MapleStory
 * KMS 1.2.160 Super Source
 * http://maple.xe.to/
 */
package tools.programs;

import packet.opcode.RecvPacketOpcode;
import packet.opcode.SendPacketOpcode;
import packet.transfer.read.ByteStream;
import packet.transfer.read.ReadingDbg;
import tools.HexTool;
import tools.Pair;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.TimeZone;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 *
 * @author TSun
 */
public class SharkConverter {

    public static void main(String[] args) {
        try {

            FileOutputStream fos = new FileOutputStream(new File("converted.txt"));


            File sharklog = new File("log.txt");
            FileInputStream fis = new FileInputStream(sharklog);
            InputStreamReader isr = new InputStreamReader(fis, Charset.forName("MS949"));
            BufferedReader reader = new BufferedReader(isr);
            String firstLine = reader.readLine();
            if (firstLine.contains("Build:") && firstLine.contains("Port:")) {
                String build = firstLine.split("Build: ")[1].substring(0, 3);
                String port = firstLine.split("Port: ")[1].split(" ===")[0];
                String head = "MapleShark Converted Log - Version : 1.2." + build + " from Port " + port;
                String head2 = "Maple Packet Analyzer for Korean MapleStory - by T-Sun\r\n\r\n";
                System.out.println(head);
                System.out.println(head2);
                fos.write(head.getBytes("MS949"));
                fos.write(System.getProperty("line.separator").getBytes("MS949"));
                fos.write(head2.getBytes("MS949"));
                fos.write(System.getProperty("line.separator").getBytes("MS949"));
                fos.write(System.getProperty("line.separator").getBytes("MS949"));
                fos.write(System.getProperty("line.separator").getBytes("MS949"));
            }
            String buffer = "";
            while ((buffer = reader.readLine()) != null) {
                String[] split = buffer.split(" == ");
                if (split[0].contains("<Inbound>")) { //SendPacket From Server
                    String headerStr = split[1].substring(0, 5);
                    headerStr = headerStr.substring(3, 5) + headerStr.substring(0, 2);
                    int header = Integer.parseInt(headerStr, 16);
                    SendPacketOpcode opcode = null;
//                    for (SendPacketOpcode spo : SendPacketOpcode.values()) {
//                        if (spo.getValue() == header) {
//                            opcode = spo;
//                            break;
//                        }
//                    }
                    switch (header) {
                        case 34:
                            opcode = SendPacketOpcode.SHOW_STATUS_INFO;
                            break;
                        case 68:
                            opcode = SendPacketOpcode.SERVERMESSAGE;
                            break;
                        case 153:
                            opcode = SendPacketOpcode.WARP_TO_MAP;
                            break;
                        case 165:
                            opcode = SendPacketOpcode.BOSS_ENV;
                            break;
                        case 269:
                            opcode = SendPacketOpcode.SHOW_ITEM_GAIN_INCHAT;
                            break;
                        case 286:
                            opcode = SendPacketOpcode.DISABLE_UI;
                            break;
                        /*case 288:
                            opcode = SendPacketOpcode.DISABLE_UI2;
                            break;*/
//                        case 274:
//                            opcode = SendPacketOpcode.UPDATE_QUEST_INFO;
//                            break;
                        case 454:
                            opcode = SendPacketOpcode.NPC_TALK;
                            break;
                    }

                    byte[] packetdata = HexTool.getByteArrayFromHexString(split[1].substring(5));
                    ReadingDbg rh = new ReadingDbg(new ByteStream(packetdata));


                    if (opcode != null) {
                        switch (opcode) {
                            case SERVERMESSAGE: {
                                byte type = rh.readByte();
                                String message = null;
                                if (type == 4) {
                                    if (rh.readByte() == 0) {
                                        break;
                                    }
                                }
                                message = rh.readMapleAsciiString();
                                byte channel = -1,
                                        megaEar = -1;
                                int itemid = 0;
                                if (type == 3 || type == 9 || type == 10) {
                                    channel = rh.readByte();
                                    megaEar = rh.readByte();
                                } else if (type == 6) {
                                    itemid = rh.readInt();
                                }
                                String outputStr = "";
                                outputStr += "SERVERMESSAGE: ";
                                outputStr += "[" + type + "] ";
                                if (itemid != 0) {
                                    outputStr += "[" + itemid + "] ";
                                }
                                if (channel != -1) {
                                    outputStr += "[CH." + channel + "] ";
                                }
                                if (megaEar != -1) {
                                    outputStr += "[Mega:" + (megaEar == 1) + "] ";
                                }
                                if (message != null) {
                                    outputStr += message;
                                }
                                System.out.println(outputStr);
                                fos.write(outputStr.getBytes("MS949"));
                                fos.write(System.getProperty("line.separator").getBytes("MS949"));
                                break;
                            }
                            case BOSS_ENV: {
                                byte type = rh.readByte();
                                String content = rh.readMapleAsciiString();
                                String outputStr = "";
                                outputStr += "BOSS_ENV: ";
                                outputStr += "[" + type + "] ";
                                outputStr += content + " ";
                                if (rh.available() > 0) {
                                    String additionalPacket = HexTool.toString(rh.read((int) rh.available()));
                                    outputStr += additionalPacket;
                                }
                                System.out.println(outputStr);
                                fos.write(outputStr.getBytes("MS949"));
                                fos.write(System.getProperty("line.separator").getBytes("MS949"));
                                break;
                            }
                            case SHOW_STATUS_INFO: {
                                byte type = rh.readByte();
                                if (type == 1) { //quest
                                    String outputStr = "";
                                    outputStr += "SHOW_STATUS_INFO: ";
                                    short quest = rh.readShort();
                                    byte type2 = rh.readByte();
                                    if (type2 == 1) { //start
                                        outputStr += "[START_QUEST] ";
                                        outputStr += "[QID:" + quest + "] ";
                                        String data = rh.readMapleAsciiString();
                                        if (data.length() > 0) {
                                            outputStr += "[DATA:" + data + "]";
                                        }
                                    } else if (type2 == 2) {
                                        outputStr += "[COMPLETE_QUEST] ";
                                        outputStr += "[QID:" + quest + "] ";
                                        long time = rh.readLong();
                                        time -= 116445060000000000L; //offset
                                        time /= 10000L;
                                        Calendar c = Calendar.getInstance(TimeZone.getTimeZone("KST"));
                                        c.setTimeInMillis(time);
                                        String date = c.getTime().toLocaleString();
                                        outputStr += "[TIME:" + date + "] ";
                                    } else if (type2 == 0) {
                                        outputStr += "[FORFEIT_QUEST] ";
                                        outputStr += "[QID:" + quest + "] ";
                                    }
                                    System.out.println(outputStr);
                                    fos.write(outputStr.getBytes("MS949"));
                                    fos.write(System.getProperty("line.separator").getBytes("MS949"));
                                } else if (type == 0x0C) { //info
                                    String outputStr = "";
                                    outputStr += "SHOW_STATUS_INFO: ";
                                    short quest = rh.readShort();
                                    String data = rh.readMapleAsciiString();
                                    outputStr += "[QID:" + quest + "] ";
                                    outputStr += "[DATA:" + data + "]";
                                    System.out.println(outputStr);
                                    fos.write(outputStr.getBytes("MS949"));
                                    fos.write(System.getProperty("line.separator").getBytes("MS949"));
                                }
                                break;
                            }
                            case SHOW_ITEM_GAIN_INCHAT: {
                                String outputStr = "";
                                outputStr += "SHOW_ITEM_GAIN_INCHAT: ";
                                byte type = rh.readByte();
                                switch (type) {
                                    case 0x5: {
                                        outputStr += "[TYPE:ITEM_GAIN_INCHAT] ";
                                        int d = rh.readByte();
                                        for (int i = 0; i < d; i++) {
                                            outputStr += "[ITEM:" + rh.readInt() + " QUANTITY:" + rh.readInt() + "] ";
                                        }
                                        break;

                                    }
                                    case 0x15:
                                    case 0x18: {
                                        outputStr += "[TYPE:WZ_EFFECT] ";
                                        outputStr += rh.readMapleAsciiString() + " ";
                                        if (rh.available() > 0) {
                                            outputStr += "[DATA:" + rh.readInt() + "] ";
                                        }
                                        break;
                                    }

                                }
                                if (!outputStr.equals("SHOW_ITEM_GAIN_INCHAT: ")) {
                                    System.out.println(outputStr);
                                    fos.write(outputStr.getBytes("MS949"));
                                    fos.write(System.getProperty("line.separator").getBytes("MS949"));
                                }
                                break;
                            }
                            case NPC_TALK: {
                                String outputStr = "";
                                outputStr += "NPC_TALK: ";
                                rh.readByte(); //4
                                outputStr += "[NPCID:" + rh.readInt() + "] ";
                                String speaker = "";
                                String dlgType = "";
                                byte msgType = rh.readByte();
                                if (msgType == 2) {
                                    dlgType = "sendYesNo";
                                } else if (msgType == 14) {
                                    dlgType = "askAcceptDecline";
                                } else {
                                    dlgType = "UNKNOWNTYPE:" + msgType;
                                }
                                String subType1 = "";
                                String message = "";
                                byte type = rh.readByte();
                                if (type != 0) {
                                    subType1 = "UNKNOWNSUBTYPE:" + type;
                                }
                                byte[] temp = rh.read((int) rh.available());
                                rh = new ReadingDbg(new ByteStream(temp));
                                ReadingDbg rh2 = new ReadingDbg(new ByteStream(temp));
                                int sd = rh2.readInt();
                                if (sd < 10000000 && sd > 1000) { //npc(speaker)
                                    rh.skip(4);
                                    speaker += "[SPEAKER:" + sd + "] ";
                                }
                                System.out.println(rh);
                                message = rh.readMapleAsciiString();
                                message = message.replace(System.getProperty("line.separator"), "\\r\\n");
                                //0D 0A
                                if (msgType == 0x10) { //send places
                                    rh.skip(8);
                                }
                                if (rh.available() == 2) {
                                    byte subType = rh.readByte();
                                    byte subType2 = rh.readByte();
                                    if (subType == 0 && subType2 == 1) {
                                        dlgType = "sendNext";
                                    } else if (subType == 1 && subType2 == 0) {
                                        dlgType = "sendPrev";
                                    } else if (subType == 1 && subType2 == 1) {
                                        dlgType = "sendNextPrev";
                                    } else if (subType == 0 && subType2 == 0) {
                                        dlgType = "sendOk";
                                    }
                                }

                                outputStr += "[" + dlgType + "] ";
                                outputStr += speaker;
                                if (!subType1.equals("")) {
                                    outputStr += "[" + subType1 + "] ";
                                }
                                outputStr += message;
                                System.out.println(outputStr);
                                fos.write(outputStr.getBytes("MS949"));
                                fos.write(System.getProperty("line.separator").getBytes("MS949"));

                                break;

                            }
                            case WARP_TO_MAP: {
                                if (rh.available() < 300) //getCharInfo check
                                {
                                    String outputStr = "";
                                    int channel = rh.readInt();
                                    rh.skip(5);
                                    outputStr += "WARP_TO_MAP: ";

                                    outputStr += "[Ch." + channel + "] ";

                                    int movetime = rh.readInt();
                                    outputStr += "[MapMove." + movetime + "] ";
                                    rh.skip(5);
                                    int mapid = rh.readInt();
                                    int spawnpoint = rh.readByte();

                                    outputStr += "[DEST MAPID:" + mapid + "] ";
                                    outputStr += "[SP:" + spawnpoint + "] ";
                                    int hp = rh.readInt();
                                    outputStr += "[HP:" + hp + "]";
                                    System.out.println(outputStr);
                                    fos.write(outputStr.getBytes("MS949"));
                                    fos.write(System.getProperty("line.separator").getBytes("MS949"));
                                }
                                break;
                            }
                            case DISABLE_UI: {
                            //case DISABLE_UI2: {

                                String outputStr = "";
                                outputStr += opcode.name() + ": ";
                                outputStr += "[LOCK : "+(rh.readByte() == 1)+"] ";
                                System.out.println(outputStr);
                                fos.write(outputStr.getBytes("MS949"));
                                fos.write(System.getProperty("line.separator").getBytes("MS949"));
                                
                                break;
                            }
                        }
                    }
                }
            }
            // CustomSharkXMLParsing();
//            FileOutputStream fos = new FileOutputStream(send);
//            FileOutputStream fos2 = new FileOutputStream(send);
//            SendPacketOpcode.loadOpcode();
//            RecvPacketOpcode.loadOpcode();



        } catch (FileNotFoundException fnfe) {
            fnfe.printStackTrace();
        } catch (IOException io) {
            io.printStackTrace();
        }

    }

    public static class SharkConfigEntry {

        public int build, opcode;
        public boolean outbound, ignore;
        public String name;

        public SharkConfigEntry(int build_, boolean outbound, int opcode, String name, boolean ignore) {
            this.build = build_;
            this.opcode = opcode;
            this.outbound = outbound;
            this.ignore = ignore;
            this.name = name;
        }
    }

    public static void CustomSharkXMLParsing() {
        boolean send = true;

        try {

            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(new FileInputStream(new File("Config.xml")));
            Node top = document.getFirstChild();
            for (int i = 0; i < top.getChildNodes().getLength(); ++i) {
                Node n = top.getChildNodes().item(i);
                if (n.getNodeName().equals("Definitions")) {
                    //found definitions
                    for (int x = 0; x < n.getChildNodes().getLength(); ++x) {
                        Node n2 = n.getChildNodes().item(x);
                        if (n2.getNodeName().equals("Definition")) {
                            for (int z = 0; z < n2.getChildNodes().getLength(); ++z) {
                                Node n3 = n2.getChildNodes().item(z);
                                System.out.println(z + "/" + n2.getChildNodes().getLength() + " - " + n3.getNodeName() + " / " + n3.getNodeValue());
                            }
                        }

                    }
                }
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
